///////////////////////////////////////////////////////////////////////////// 
/* 
  Copyright 2001 Ronald S. Burkey 
 
  This file is part of GutenMark. 
 
  GutenMark is free software; you can redistribute it and/or modify 
  it under the terms of the GNU General Public License as published by 
  the Free Software Foundation; either version 2 of the License, or 
  (at your option) any later version. 
 
  GutenMark is distributed in the hope that it will be useful, 
  but WITHOUT ANY WARRANTY; without even the implied warranty of 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  GNU General Public License for more details. 
 
  You should have received a copy of the GNU General Public License 
  along with GutenMark; if not, write to the Free Software 
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 
  Filename:	AddMarkup.c 
  Purpose:	Adds a markup record to the temporary markup file. 
  Mods:		01/01/02 RSB	Split off from MarkBody.c. 
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "AutoMark.h"

//----------------------------------------------------------------------- 
// Add a markup record to the markup file.  Returns 0 on success. 
// This function plays a slightly more complex role than it would seem 
// at first glance.  The markup file must be sorted in order of increasing 
// offsets into the original etext, and in almost all cases the program  
// actually tries to add the markup in this order.  However, there is a 
// small number of cases (right now, involving only italicizing foreign 
// text) in which the program finds it necessary to insert a markup record 
// a few records back.  Rather than applying some complex logic to track 
// this, or sorting the (large) markup file at the end of the process, 
// we take care of this completely within AddMarkup.   
// 
// If called with Offset == -1, AddMarkup's internal buffer (if any) is  
// instead flushed to disk, so that the file can be safely closed. 
// 
// Returns 0 on success. 
static long LastOffset = -1;	// Max offset used so far. 
int
AddMarkup (AnalysisDataset * Dataset, long Offset, enum MarkupType Type,
	   char Insert)
{
  if (Offset >= 0)
    {
      MarkupRecord Record;
      Record.Offset = Offset;
      Record.Type = Type;
      Record.Insert = Insert;

      // If the Offset of the new markup is less than the Offset of 
      // previous markup, we need to backtrack in the output file, 
      // so as to insert the record at the proper point.  The seeking 
      // is inefficient, but we expect to do it very seldom, and for  
      // only a few record-positions. 
      if (Offset < LastOffset)
	{
	  long CurrentPos;
	  int NumRecs;
	  MarkupRecord CheckRecord, *TempRecords;
	  NumRecs = 0;
	  do
	    {
	      if (fseek
		  (Dataset->MarkupFile, -sizeof (CheckRecord), SEEK_CUR))
		return (1);
	      if (1 !=
		  fread (&CheckRecord, sizeof (CheckRecord), 1,
			 Dataset->MarkupFile))
		return (1);
	      if (fseek
		  (Dataset->MarkupFile, -sizeof (CheckRecord), SEEK_CUR))
		return (1);
	      NumRecs++;
	    }
	  while (CheckRecord.Offset > Offset);
	  if (fseek (Dataset->MarkupFile, sizeof (CheckRecord), SEEK_CUR))
	    return (1);
	  NumRecs--;
	  CurrentPos = ftell (Dataset->MarkupFile);
	  TempRecords =
	    (MarkupRecord *) calloc (NumRecs, sizeof (MarkupRecord));
	  if (TempRecords == NULL)
	    return (2);
	  if (NumRecs !=
	      fread (TempRecords, sizeof (MarkupRecord), NumRecs,
		     Dataset->MarkupFile))
	    return (1);
	  if (fseek (Dataset->MarkupFile, CurrentPos, SEEK_SET))
	    return (1);
	  if (1 !=
	      fwrite (&Record, sizeof (MarkupRecord), 1, Dataset->MarkupFile))
	    return (1);
	  if (NumRecs !=
	      fwrite (TempRecords, sizeof (MarkupRecord), NumRecs,
		      Dataset->MarkupFile))
	    return (1);
	}
      else
	{
	  if (1 != fwrite (&Record, sizeof (Record), 1, Dataset->MarkupFile))
	    return (1);
	  LastOffset = Offset;
	}
    }
  return (0);
}
